#include <qqtuseronlinemanager.h>

#include <qqthostaddressmanager.h>

enum MsgSecName
{
    CMD_TYPE = 0,
    CMD_CONTENT,
    CMD_MAX
};

QQtUserOnlineServerManager::QQtUserOnlineServerManager ( QObject* parent ) : QObject ( parent )
{
    s0 = new QQtUdpServer ( this );
    m0 = new QQtUserOnlineServerProtocolManager ( this );
    m0->registerProtocol<QQtUserOnlineServerProtocol>();
    s0->installProtocolManager ( m0 );

    connect ( m0, SIGNAL ( remainingProtocolChanged ( int ) ),
              this, SLOT ( remainingProtocolChanged ( int ) ) );

    connect ( m0, SIGNAL ( signalUserInformationChanged ( const QQtDictionary& ) ),
              this, SIGNAL ( signalUserInformationChanged ( const QQtDictionary& ) ) );

    QQtHostAddressManager manager;
    QString ip = manager.getHostAddress();
    int port = 4412;
#if USE_HOST_ADDRESS
    s0->bind ( QHostAddress ( ip ), port, QQtUdpServer::DefaultForPlatform );
#else
    s0->bind ( port, QQtUdpServer::DefaultForPlatform );
#endif
    p3line() << s0->localAddress() << s0->localPort();


    QUuid quuid = QUuid::createUuid();
    QString uuid = quuid.toString().left ( 14 ).mid ( 1 );
    //qDebug() << uuid;
    setUUid ( uuid );

    setLocalIpPort ( ip, port );

    setUserName ( "Default" );
}

QQtUserOnlineServerManager::~QQtUserOnlineServerManager() {}

void QQtUserOnlineServerManager::setListeningAddress ( QHostAddress address, int port )
{
    s0->disconnectFromHost();
    s0->bind ( address, port, QQtUdpServer::DefaultForPlatform );
    p3line() << s0->localAddress() << s0->localPort();
    QString ip = address.toString();
    setLocalIpPort ( ip, port );
}

void QQtUserOnlineServerManager::setListeningPort ( int port )
{
    s0->disconnectFromHost();
    QQtHostAddressManager manager;
    QString ip = manager.getHostAddress();
#if USE_HOST_ADDRESS
    s0->bind ( QHostAddress ( ip ), port, QQtUdpServer::DefaultForPlatform );
#else
    s0->bind ( port, QQtUdpServer::DefaultForPlatform );
#endif
    p3line() << s0->localAddress() << s0->localPort();

    setLocalIpPort ( ip, port );
}

void QQtUserOnlineServerManager::setLocalIpPort ( QString ip, int port )
{
    mIP = ip;
    mPort = port;
    m0->setLocalIpPort ( ip, port );
}

void QQtUserOnlineServerManager::setUUid ( QString uuid )
{
    mUUid = uuid;
    m0->setUUid ( uuid );
}

void QQtUserOnlineServerManager::remainingProtocolChanged ( int num )
{
    if ( num > 10 )
        return;
    m0->registerProtocol<QQtUserOnlineServerProtocol>();
}


void QQtUserOnlineServerManager::setUserName ( QString username )
{
    mUserName = username;
    m0->setUserName ( username );
}

void QQtUserOnlineServerManager::setUserContent ( QString key, QString content )
{
    mUserContent[key] = content;
    m0->setUserContent ( key, content );
}

QString QQtUserOnlineServerManager::getUserName()
{
    return mUserName;
}

QString QQtUserOnlineServerManager::getUserContent ( QString key )
{
    return mUserContent[key].getValue().toString();
}

QQtDictionary& QQtUserOnlineServerManager::userDict()
{
    return m0->getUserDict();
}

QQtUserOnlineManager::QQtUserOnlineManager ( QObject* parent ) : QObject ( parent )
{
    c0 = new QQtUdpClient ( this );
    p0 = new QQtUserOnlineProtocol ( this );
    c0->installProtocol ( p0 );

    connect ( p0, SIGNAL ( signalServerInformation ( const QQtDictionary& ) ),
              this, SIGNAL ( signalServerInformation ( const QQtDictionary& ) ) );
    connect ( p0, SIGNAL ( signalUserInformation ( const QQtDictionary& ) ),
              this, SIGNAL ( signalUserInformation ( const QQtDictionary& ) ) );

    c0->setServerAddress ( QHostAddress ( QHostAddress::Any ), 4412 );

    QQtHostAddressManager manager;
    QString ip = manager.getHostAddress();
    int port = 4411;
#if USE_HOST_ADDRESS
    c0->bind ( QHostAddress ( ip ), port, QQtUdpClient::DefaultForPlatform );
#else
    c0->bind ( port, QQtUdpClient::DefaultForPlatform );
#endif
    p3line() << c0->localAddress() << c0->localPort();

    QUuid quuid = QUuid::createUuid();
    QString uuid = quuid.toString().left ( 14 ).mid ( 1 );
    //qDebug() << uuid;
    setUUid ( uuid );

    setLocalIpPort ( ip, port );

    setUserName ( "Default" );
}

QQtUserOnlineManager::~QQtUserOnlineManager() {}

void QQtUserOnlineManager::setServerAddress ( QHostAddress address, int port )
{
    c0->setServerAddress ( address, port );
}

void QQtUserOnlineManager::setListeningAddress ( QHostAddress address, int port )
{
    c0->disconnectFromHost();
    c0->bind ( address, port, QQtUdpClient::DefaultForPlatform );
    QString ip = address.toString();
    setLocalIpPort ( ip, port );
    p3line() << c0->localAddress() << c0->localPort();

}

void QQtUserOnlineManager::setListeningPort ( int port )
{
    c0->disconnectFromHost();
    QQtHostAddressManager manager;
    QString ip = manager.getHostAddress();
#if USE_HOST_ADDRESS
    c0->bind ( QHostAddress ( ip ), port, QQtUdpClient::DefaultForPlatform );
#else
    c0->bind ( port, QQtUdpClient::DefaultForPlatform );
#endif
    p3line() << c0->localAddress() << c0->localPort();
    setLocalIpPort ( ip, port );
}

void QQtUserOnlineManager::setLocalIpPort ( QString ip, int port )
{
    mIP = ip;
    mPort = port;
    p0->setIPPort ( ip, port );
}

void QQtUserOnlineManager::setUUid ( QString uuid )
{
    mUUid = uuid;
    p0->setUUid ( uuid );
}

void QQtUserOnlineManager::setUserName ( QString username )
{
    mUserName = username;
    p0->setUserName ( username );
}

void QQtUserOnlineManager::setUserContent ( QString key, QString content )
{
    mUserContent[key] = content;
    p0->setUserContent ( key, content );
}

void QQtUserOnlineManager::sendRequestServerInformation()
{
    p0->sendReqServerInformation();
}

void QQtUserOnlineManager::sendRequestUserInformation()
{
    p0->sendReqInformation();
}

void QQtUserOnlineManager::sendInformation()
{
    p0->sendInformation();
}

void QQtUserOnlineManager::sendLogin()
{
    p0->sendLogin();
}

void QQtUserOnlineManager::sendLogout()
{
    p0->sendLogout();
}

QQtUserOnlineServerProtocolManager::QQtUserOnlineServerProtocolManager ( QObject* parent )
    : QQtProtocolManager ( parent )
{
    connect ( this, SIGNAL ( notifyToBusinessLevel ( const QQtProtocol*, const QQtMessage* ) ),
              this, SLOT ( slotProcessingUserRequest ( const QQtProtocol*, const QQtMessage* ) ) );


    m_timer = new QTimer ( this );
    m_timer->setSingleShot ( false );
    m_timer->setInterval ( 10000 );
    connect ( m_timer, SIGNAL ( timeout() ), this, SLOT ( slotTimeout() ) );
    m_timer->start();
}

QQtUserOnlineServerProtocolManager::~QQtUserOnlineServerProtocolManager() {}

void QQtUserOnlineServerProtocolManager::setLocalIpPort ( QString ip, int port )
{
    mIP = ip;
    mPort = port;
}

void QQtUserOnlineServerProtocolManager::setUUid ( QString uuid )
{
    mUUid = uuid;
}

void QQtUserOnlineServerProtocolManager::setUserName ( QString username )
{
    mUserName = username;
}

void QQtUserOnlineServerProtocolManager::setUserContent ( QString key, QString content )
{
    mUserContent[key] = content;
}

QQtDictionary& QQtUserOnlineServerProtocolManager::getUserDict()
{
    return mDictUser;
}

void QQtUserOnlineServerProtocolManager::slotRecvUserInformation ( const QQtDictionary& data )
{
    QString uuid = data["uuid"].getValue().toString();

    QQtDictionaryMapIterator itor ( data.getMap() );
    while ( itor.hasNext() )
    {
        itor.next();
        const QString& key = itor.key();
        const QQtDictionary& value = itor.value();

        mDictUser[uuid][key] = data[key];
    }

    emit signalUserInformationChanged ( mDictUser );
    qDebug() << qPrintable ( mDictUser.toJson ( QJsonDocument::Indented ) );
}

void QQtUserOnlineServerProtocolManager::slotProcessingUserRequest ( const QQtProtocol* self,
                                                                     const QQtMessage* message )
{
    QQtUserOnlineServerProtocol* protocol = ( QQtUserOnlineServerProtocol* ) self;
    QQtDataSerialization* dataserial = ( QQtDataSerialization* ) message;
    QQtDataSerialization& ds0 = *dataserial;
    QString cmd_type = ds0[CMD_TYPE].getValue().toString();
    p3line() << cmd_type;
    if ( cmd_type == "req_information" )
    {
        protocol->sendRspInformation ( mDictUser );
    }
    else if ( cmd_type == "heartbeats" )
    {
        QString uuid = ds0[CMD_CONTENT]["uuid"].getValue().toString();
        mDictUser[uuid]["heartbeats"] = 1;
    }
}

void QQtUserOnlineServerProtocolManager::slotTimeout()
{
    QStringList list1;
    QQtDictionaryMapIterator itor ( mDictUser.getMap() );
    while ( itor.hasNext() )
    {
        itor.next();
        const QString& key = itor.key();
        const QQtDictionary& value = itor.value();
        int hb0 = mDictUser[key]["heartbeats"].getValue().toInt();
        if ( hb0 != 0 )
        {
            //online
            mDictUser[key]["heartbeats"] = 0;
            //qDebug() << key << "online";
        }
        else
        {
            //offline
            list1.push_back ( key );
            qDebug() << key << "offline";
        }
    }

    QListIterator<QString> itor1 ( list1 );
    while ( itor1.hasNext() )
    {
        const QString& key = itor1.next();
        mDictUser.getMap().remove ( key );
    }

    emit signalUserInformationChanged ( mDictUser );
}

QQtProtocol* QQtUserOnlineServerProtocolManager::createProtocol()
{
    QQtUserOnlineServerProtocol* p = ( QQtUserOnlineServerProtocol* ) QQtProtocolManager::createProtocol();
    connect ( p, SIGNAL ( signalRecvUserInformation ( QQtDictionary ) ),
              this, SLOT ( slotRecvUserInformation ( QQtDictionary ) ) );

    p->setIPPort ( mIP, mPort );
    p->setUUid ( mUUid );
    p->setUserName ( mUserName );
    QQtDictionaryMapIterator itor ( mUserContent.getMap() );
    while ( itor.hasNext() )
    {
        itor.next();
        const QString& key = itor.key();
        const QQtDictionary& value = itor.value();
        QString vvv = value.getValue().toString();
        p->setUserContent ( key, vvv );
    }
    return p;
}

QQtUserOnlineServerProtocol::QQtUserOnlineServerProtocol ( QObject* parent )
    : QQtDataProtocol ( parent ) {}

QQtUserOnlineServerProtocol::~QQtUserOnlineServerProtocol() {}

void QQtUserOnlineServerProtocol::setIPPort ( QString ip, int port )
{
    mIP = ip;
    mPort = port;
}

void QQtUserOnlineServerProtocol::setUUid ( QString uuid )
{
    mUUid = uuid;
}

void QQtUserOnlineServerProtocol::setUserName ( QString username )
{
    mUserName = username;
}

void QQtUserOnlineServerProtocol::setUserContent ( QString key, QString content )
{
    mUserContent[key] = content;
}

void QQtUserOnlineServerProtocol::recvUserInformation ( const QQtDictionary& data )
{
    emit signalRecvUserInformation ( data );
}

void QQtUserOnlineServerProtocol::recvReqServerInformation()
{
    sendServerInformation();
}

void QQtUserOnlineServerProtocol::sendServerInformation()
{
    QQtDataSerialization data;
    data[CMD_TYPE] = "rsp_server_information";
    data[CMD_CONTENT]["ip"] = mIP;
    data[CMD_CONTENT]["port"] = mPort;
    data[CMD_CONTENT]["uuid"] = mUUid;
    data[CMD_CONTENT]["user_name"] = mUserName;
    data[CMD_CONTENT]["user_content"] = mUserContent;
    data[CMD_CONTENT]["heartbeats"] = 1;
    data.serialize();
    p3line() << data[CMD_TYPE].getValue().toString() << mIP << mPort;
    sendMessage ( data );
}

void QQtUserOnlineServerProtocol::recvReqInformation ( const QQtDataSerialization& message )
{
    notifyToProtocolManager ( this,  &message );
}

void QQtUserOnlineServerProtocol::sendRspInformation ( const QQtDictionary& dictUser )
{

    QQtDataSerialization data;
    data[CMD_TYPE] = "rsp_information";

    QQtDictionaryMapIterator itor ( dictUser.getMap() );
    while ( itor.hasNext() )
    {
        itor.next();
        const QString& key = itor.key();
        const QQtDictionary& value = itor.value();
        QString uuid = key;
        data[CMD_CONTENT][uuid]["ip"] = value["ip"];
        data[CMD_CONTENT][uuid]["port"] = value["port"];
        data[CMD_CONTENT][uuid]["uuid"] = value["uuid"];
        data[CMD_CONTENT][uuid]["user_name"] = value["user_name"];
        data[CMD_CONTENT][uuid]["user_content"] = value["user_content"];
        data[CMD_CONTENT][uuid]["heartbeats"] = value["heartbeats"];
    }
    data.serialize();
    data.dump();
    data.dump_dictionary();
    p3line() << data[CMD_TYPE].getValue().toString() << mIP << mPort;
    sendMessage ( data );
}

void QQtUserOnlineServerProtocol::recvMessage ( const QQtDataSerialization& data )
{
    QQtDataSerialization ds0 = data;
    QString cmd_type = ds0[CMD_TYPE].getValue().toString();
    p3line() << cmd_type;
    if ( cmd_type == "login"
         || cmd_type == "logout"
         || cmd_type == "heartbeats"
         || cmd_type == "information" )
    {
        QQtDictionary& data_section = ds0[CMD_CONTENT];
        recvUserInformation ( data_section );
    }
    else if ( cmd_type == "req_information" )
    {
        recvReqInformation ( ds0 );
    }
    else if ( cmd_type == "req_server_information" )
    {
        recvReqServerInformation();
    }
}

QQtUserOnlineProtocol::QQtUserOnlineProtocol ( QObject* parent )
    : QQtDataProtocol ( parent )
{

    m_timer = new QTimer ( this );
    m_timer->setSingleShot ( false );
    m_timer->setInterval ( 5000 );
    connect ( m_timer, SIGNAL ( timeout() ), this, SLOT ( slotTimeout() ) );
}

QQtUserOnlineProtocol::~QQtUserOnlineProtocol() {}

void QQtUserOnlineProtocol::setIPPort ( QString ip, int port )
{
    mIP = ip;
    mPort = port;
}

void QQtUserOnlineProtocol::setUUid ( QString uuid )
{
    mUUid = uuid;
}

void QQtUserOnlineProtocol::setUserName ( QString username )
{
    mUserName = username;
}

void QQtUserOnlineProtocol::setUserContent ( QString key, QString content )
{
    mUserContent[key] = content;
}

void QQtUserOnlineProtocol::sendLogin()
{
    QQtDataSerialization data;
    data[CMD_TYPE] = "login";
    data[CMD_CONTENT]["ip"] = mIP;
    data[CMD_CONTENT]["port"] = mPort;
    data[CMD_CONTENT]["uuid"] = mUUid;
    data[CMD_CONTENT]["user_name"] = mUserName;
    data[CMD_CONTENT]["user_content"] = mUserContent;
    data[CMD_CONTENT]["heartbeats"] = 1;
    data.serialize();
    p3line() << data[CMD_TYPE].getValue().toString() << mIP << mPort;
    sendMessage ( data );
    m_timer->start();
}

void QQtUserOnlineProtocol::sendLogout()
{
    QQtDataSerialization data;
    data[CMD_TYPE] = "logout";
    data[CMD_CONTENT]["ip"] = mIP;
    data[CMD_CONTENT]["port"] = mPort;
    data[CMD_CONTENT]["uuid"] = mUUid;
    data[CMD_CONTENT]["user_name"] = mUserName;
    data[CMD_CONTENT]["user_content"] = mUserContent;
    data[CMD_CONTENT]["heartbeats"] = 0;
    data.serialize();
    p3line() << data[CMD_TYPE].getValue().toString() << mIP << mPort;
    sendMessage ( data );
    m_timer->stop();
}

void QQtUserOnlineProtocol::sendInformation()
{
    QQtDataSerialization data;
    data[CMD_TYPE] = "information";
    data[CMD_CONTENT]["ip"] = mIP;
    data[CMD_CONTENT]["port"] = mPort;
    data[CMD_CONTENT]["uuid"] = mUUid;
    data[CMD_CONTENT]["user_name"] = mUserName;
    data[CMD_CONTENT]["user_content"] = mUserContent;
    data[CMD_CONTENT]["heartbeats"] = 1;
    data.serialize();
    p3line() << data[CMD_TYPE].getValue().toString() << mIP << mPort;
    sendMessage ( data );
}

void QQtUserOnlineProtocol::sendHeartbeats()
{
    QQtDataSerialization data;
    data[CMD_TYPE] = "heartbeats";
    data[CMD_CONTENT]["ip"] = mIP;
    data[CMD_CONTENT]["port"] = mPort;
    data[CMD_CONTENT]["uuid"] = mUUid;
    data[CMD_CONTENT]["user_name"] = mUserName;
    data[CMD_CONTENT]["user_content"] = mUserContent;
    data[CMD_CONTENT]["heartbeats"] = 1;
    data.serialize();
    p3line() << data[CMD_TYPE].getValue().toString() << mIP << mPort;
    sendMessage ( data );
}

void QQtUserOnlineProtocol::sendReqInformation()
{
    QQtDataSerialization data;
    data[CMD_TYPE] = "req_information";
    data[CMD_CONTENT]["ip"] = mIP;
    data[CMD_CONTENT]["port"] = mPort;
    data[CMD_CONTENT]["uuid"] = mUUid;
    data[CMD_CONTENT]["user_name"] = mUserName;
    data[CMD_CONTENT]["user_content"] = mUserContent;
    data[CMD_CONTENT]["heartbeats"] = 1;
    data.serialize();
    p3line() << data[CMD_TYPE].getValue().toString() << mIP << mPort;
    sendMessage ( data );
}

void QQtUserOnlineProtocol::sendReqServerInformation()
{
    QQtDataSerialization data;
    data[CMD_TYPE] = "req_server_information";
    data[CMD_CONTENT]["ip"] = mIP;
    data[CMD_CONTENT]["port"] = mPort;
    data[CMD_CONTENT]["uuid"] = mUUid;
    data[CMD_CONTENT]["user_name"] = mUserName;
    data[CMD_CONTENT]["user_content"] = mUserContent;
    data[CMD_CONTENT]["heartbeats"] = 1;
    data.serialize();
    p3line() << data[CMD_TYPE].getValue().toString() << mIP << mPort;
    sendMessage ( data );
}

void QQtUserOnlineProtocol::slotTimeout()
{
    sendHeartbeats();
}

void QQtUserOnlineProtocol::recvMessage ( const QQtDataSerialization& data )
{
    QQtDataSerialization ds0 = data;
    QString cmd_type = ds0[CMD_TYPE].getValue().toString();
    p3line() << cmd_type;
    if ( cmd_type == "rsp_information" )
    {
        QQtDictionary& data_section = ds0[CMD_CONTENT];
        emit signalUserInformation ( data_section );
    }
    else if ( cmd_type == "rsp_server_information" )
    {
        QQtDictionary& data_section = ds0[CMD_CONTENT];
        emit signalServerInformation ( data_section );
    }
}
